/** <!--------------------------------------------------------------------------------------------->
 * @file XXXXXXX.XXX
 *
 * GSvn - A Graphical Client for SVN
 * Copyright (C) 2012  Karl Krach, gsvn@bluespirit.la
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 <!---------------------------------------------------------------------------------------------> */

// -- includes --
#include "GraphRevision.h"
#include "GraphBranch.h"
#include <QMenu>
#include <QAction>
#include <QPainter>
#include <QGraphicsDropShadowEffect>
#include <QGraphicsSceneContextMenuEvent>
#include <QDebug>
#include "GeometryChangeListener.h"
#include <QTimer>


const QColor GraphRevision::S_BLUE_COLOR(83, 167, 226);


GraphRevision::GraphRevision( GraphBranch* pParent, QString strName ) : GraphItem(strName),
    m_strName(strName), m_iOffset(3), m_bTinyMode(false),m_bHasFocus(false),
    m_pGeometryChangeListener(NULL), m_pMenu(new QMenu()), m_iZValue(0)
{
	setFlag( QGraphicsItem::ItemIsFocusable, true );
	setFlag( QGraphicsItem::ItemIsMovable, true );

	m_pShadowEffect = new QGraphicsDropShadowEffect();
	ApplyOffset( m_iOffset );
	// assign effect and pass over ownership
	setGraphicsEffect( m_pShadowEffect );


	QAction* pBlueAction = m_pMenu->addAction("Blue");
	pBlueAction->setCheckable( true );
	pBlueAction->setChecked( true );
	connect( pBlueAction, SIGNAL(triggered()), this, SLOT(SetBlue()) );
	QAction* pOranAction = m_pMenu->addAction("Orange");
	pOranAction->setCheckable( true );
	connect( pOranAction, SIGNAL(triggered()), this, SLOT(SetOrange()) );

	QActionGroup* pGroup = new QActionGroup( this );
	pGroup->setExclusive( true );
	pGroup->addAction( pBlueAction );
	pGroup->addAction( pOranAction );

	SetBlue();
	//
	// Need this workaround to be able to react on QGraphicsItem::ItemChildAddedChange
	//
	setParentItem(pParent);
}

GraphRevision::~GraphRevision()
{
	if( m_pMenu != NULL )
	{
		delete m_pMenu;
		m_pMenu = NULL;
	}
}

QVariant GraphRevision::itemChange( GraphicsItemChange eChange, const QVariant& oValue )
{
	if( eChange == QGraphicsItem::ItemParentHasChanged )
	{
		m_pGeometryChangeListener = NULL;
		QGraphicsItem* pItem = oValue.value<QGraphicsItem*>();
		GeometryChangeListener* pChangeListener = dynamic_cast<GeometryChangeListener*>(pItem);
		if( pChangeListener )
		{
			m_pGeometryChangeListener = pChangeListener;
		}
	}
	else if( eChange == QGraphicsItem::ItemEnabledHasChanged )
	{
		if( oValue.value<bool>() )
		{
			ApplyOffset( m_iOffset );
		}
		else
		{
			ApplyOffset( 1 );
		}
	}
	return QGraphicsItem::itemChange( eChange, oValue );
}

void GraphRevision::mouseMoveEvent( QGraphicsSceneMouseEvent* event )
{
	if( m_oMoveStart.isNull() )
		m_oMoveStart = mapToScene(event->lastPos());

	return QGraphicsItem::mouseMoveEvent( event );
}

void GraphRevision::mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
{
	if( !m_oMoveStart.isNull() )
	{
		setPos( m_oMoveStart - mapToScene(event->pos()) + pos() );
		m_oMoveStart = QPointF();
	}

	return QGraphicsItem::mouseReleaseEvent( event );
}


void GraphRevision::focusInEvent( QFocusEvent* )
{
	prepareGeometryChange();
	m_iZValue = zValue();
	setZValue( 100 );
	ApplyOffset( 12 );
	m_bHasFocus = true;
}

void GraphRevision::focusOutEvent( QFocusEvent* )
{
	prepareGeometryChange();
	ApplyOffset( m_iOffset );
	setZValue( m_iZValue );
	m_bHasFocus = false;
}

void GraphRevision::mouseDoubleClickEvent( QGraphicsSceneMouseEvent* )
{
	prepareGeometryChange();
	m_bTinyMode = !m_bTinyMode;
	m_pGeometryChangeListener->GeometryHasChanged();
}

void GraphRevision::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
	m_pMenu->exec(event->screenPos());
}

QRectF GraphRevision::boundingRect() const
{
	if( m_bTinyMode )
	{
		return QRectF( S_TINY_WIDTH  / -2.0f,
		               S_TINY_HEIGHT / -2.0f,
		               S_TINY_WIDTH,
		               S_TINY_HEIGHT
		             );
	}
	else
	{
		return QRectF( S_FULL_WIDTH / -2.0f,
		               S_FULL_HEIGHT / -2.0f,
		               S_FULL_WIDTH,
		               S_FULL_HEIGHT
		             );
	}
}

void GraphRevision::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
	Q_UNUSED(option);
	Q_UNUSED(widget);

	painter->save();

	painter->setBrush( m_oColor );
	painter->setPen( Qt::NoPen );
	if( m_bTinyMode )
	{
		QPoint oCenter(0,0);
		if( m_bHasFocus ) oCenter -= QPoint(3, 3);
		painter->drawEllipse( oCenter, S_TINY_WIDTH / 2, S_TINY_HEIGHT / 2 );
	}
	else
	{
		QRectF oRect( S_FULL_WIDTH / -2.0f,
		              S_FULL_HEIGHT / -2.0f,
                      S_FULL_WIDTH, S_FULL_HEIGHT
		             );
		if( m_bHasFocus ) oRect.translate( -3, -3 );
		float fRadius = (S_FULL_WIDTH + S_FULL_HEIGHT) / 20.0f;
		painter->drawRoundedRect( oRect, fRadius, fRadius);
		painter->setBrush( Qt::NoBrush );
		painter->setPen( QColor( Qt::black ) );
		painter->drawText( oRect.adjusted( oRect.width()* 0.1, oRect.height()* 0.1,
		                                   oRect.width()*-0.1, oRect.height()*-0.1), Qt::AlignCenter,
		                   m_strName + "\nCharly\n2012-01-14" );
	}

	painter->restore();
}

void GraphRevision::SetOrange()
{
	m_oColor = QColor( 255-S_BLUE_COLOR.red(),
	                   255-S_BLUE_COLOR.green(),
	                   255-S_BLUE_COLOR.blue()
	                 );
}

void GraphRevision::SetBlue()
{
	m_oColor = S_BLUE_COLOR;
}

void GraphRevision::ApplyOffset( const int iOffset )
{
	m_pShadowEffect->setOffset( iOffset / 2.0, iOffset / 2.0 );
	m_pShadowEffect->setBlurRadius( iOffset * 3 );
}
